package com.bj58.ecdata.dashboard.databll;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bj58.ecdata.dao.util.Common;
import com.bj58.ecdata.dashboard.cache.ServiceBeanFactory;
import com.bj58.ecdata.dashboard.constant.EnumCate;
import com.bj58.ecdata.dashboard.constant.EnumCity;
import com.bj58.ecdata.dashboard.constant.EnumPageType;
import com.bj58.ecdata.dashboard.constant.EnumPlatform;
import com.bj58.ecdata.dashboard.constant.EnumSource;
import com.bj58.ecdata.dashboard.constant.NetFlowIndex;
import com.bj58.ecdata.dashboard.dbentity.NetFlow;
import com.bj58.ecdata.dashboard.dbentity.NetFlowCate;
import com.bj58.ecdata.dashboard.dbentity.NetFlowCity;
import com.bj58.ecdata.dashboard.dbentity.NetFlowCityCate;
import com.bj58.ecdata.dashboard.dbentity.NetFlowMAU;
import com.bj58.ecdata.dashboard.dbentity.NetFlowSource;
import com.bj58.ecdata.dashboard.dbentity.NetFlowSource_Three;
import com.bj58.ecdata.dashboard.dbentity.SearchWord;
import com.bj58.ecdata.dashboard.dbentity.SearchWord_M;
import com.bj58.ecdata.dashboard.dbentity.SourceFlow;
import com.bj58.ecdata.dashboard.dbentity.TrafficFlow;
import com.bj58.ecdata.dashboard.dbentity.VisitPath;
import com.bj58.ecdata.dashboard.dbentity.VisitPathNew;
import com.bj58.ecdata.dashboard.service.AbstractBaseService;
import com.bj58.ecdata.dashboard.utils.DDateUtils;
import com.bj58.ecdata.dashboard.utils.DNumberUtils;
import com.bj58.ecdata.dashboard.utils.ReflectUtil;
import com.bj58.ecdata.dashboard.utils.VelocityTools;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;

/**
 * 
 * 流量统计计算逻辑
 * 
 * <p>
 * detailed comment
 * 
 * @author zhaoxiang 2015-1-26
 * @see
 * @since 1.0
 */
public class NetFlowBLL {
	
	private static AbstractBaseService<NetFlow> nfService =ServiceBeanFactory.get(NetFlow.class,null);
	private static AbstractBaseService<NetFlowCity> nfCityService = ServiceBeanFactory.get(NetFlowCity.class,null);
	private static AbstractBaseService<SearchWord> searchWordService = ServiceBeanFactory.get(SearchWord.class,null);
	private static AbstractBaseService<SearchWord_M> searchWordService_M = ServiceBeanFactory.get(SearchWord_M.class,null);
	private static AbstractBaseService<NetFlowSource> nfSourceService = ServiceBeanFactory.get(NetFlowSource.class,null);
	private static AbstractBaseService<NetFlowSource_Three> nfSourceThreeService = ServiceBeanFactory.get(NetFlowSource_Three.class,null);
	private static AbstractBaseService<NetFlowCate> nfCateService = ServiceBeanFactory.get(NetFlowCate.class,null);
	private static AbstractBaseService<NetFlowMAU> mauService = ServiceBeanFactory.get(NetFlowMAU.class,null);
	private static AbstractBaseService<VisitPath> visitPathService = ServiceBeanFactory.get(VisitPath.class,null);
	private static AbstractBaseService<VisitPathNew> visitPathNewService = ServiceBeanFactory.get(VisitPathNew.class,null);
	private static AbstractBaseService<TrafficFlow> trafficFlowService = ServiceBeanFactory.get(TrafficFlow.class,null);
	private static AbstractBaseService<SourceFlow> sourceFlowService = ServiceBeanFactory.get(SourceFlow.class,null);
	private static final String PATTEN_GENERAL = "(stat_date = '%s' OR stat_date='%s' OR stat_date='%s' OR stat_date='%s') AND business_name='%s'";

	/**
	 * 根据属性名获取值,会缓存类信息，在大量反射的情况下,性能会显著提高
	 * @param vo
	 * @param column
	 * @return
	 */
	private static <T>  Object getVal(T vo, String column) {
		try {
			if (vo == null) {
				return null;
			}
//			Field field= Common.getFieldByName(clas, column); curVal =  FieldUtils.readField(field,vo,true);
			Method getM = Common.getGetterMethod(vo.getClass(), column);
			if(!getM.isAccessible()){
				getM.setAccessible(true);	//快速访问，不进行安全检查,据说在大量反射的情况下,可以提升性能20倍以上
			}
			Object curVal = getM.invoke(vo); //比field.get(vo)效率高
			if("stat_date".equals(column)){
				
				return DDateUtils.formatDay((Date) curVal);
			}
			return curVal;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	
	
	private static <T> Number getNetFlowValue(T vo,NetFlowIndex index){
		//index为null时会报空指针异常,根本不会去执行default,因为对于枚举型，编译器会根据它的值进行匹配：调用enum.ordinal()方法。
		switch (index) {
			case pv:
			case vppv:
			case lide_pv:
				return (Long) getVal(vo,"pv");
			case uv:
			case lide_uv:
				return (Long) getVal(vo,"uv");
			case pvDIVuv:
				double pvDIVuv = DNumberUtils.formatDouble((Double) getVal(vo,"pvDIVuv"));
				return pvDIVuv;
			case vppvDIVuv:
				double vppvDIVuv = DNumberUtils.formatDouble((Double) getVal(vo,"vppvDIVuv"));
				return vppvDIVuv;
			default:
				break;
		}
		return 0;
	}
	
	/**
	 * 查询某日总体情况并计算日环比 周同比 月同比
	 * 
	 * @param date
	 *            --要查询的日期
	 * @param cate
	 *            --要查询的类别
	 * @return
	 * @author guolu 2015-1-26
	 */
	public static List<List<String>> getGeneral(Date date, EnumCate cate) {
		if (date == null || cate == null) {
			return Collections.emptyList();
		}

		String now = DDateUtils.formatDay(date);
		String lastDay = DDateUtils.formatDay(DDateUtils.getLastDay(date));// 计算日环比
		String lastWeek = DDateUtils.formatDay(DDateUtils.getLastWeek(date));// 计算周同比
		String lastMonth = DDateUtils.formatDay(DateUtils.addDays(date, -28));// 计算月同比 , 按28天算，刚好4周

		// 查询条件
		String condition = String.format(PATTEN_GENERAL, now, lastDay, lastWeek, lastMonth, cate.getDBName());

		// 查询结果
		List<NetFlow> list = nfService.getListByConditon(null, condition, null);

		Map<String, List<NetFlow>> map = groupByField(list,"stat_date");

		// 当天没有数据查前一天数据
		if (map.get(now) == null || map.get(now).isEmpty()) {
			date = DDateUtils.getLastDay(date);
			now = DDateUtils.formatDay(date);
			lastDay = DDateUtils.formatDay(DDateUtils.getLastDay(date));// 计算日环比
			lastWeek = DDateUtils.formatDay(DDateUtils.getLastWeek(date));// 计算周同比
			lastMonth = DDateUtils.formatDay(DDateUtils.getLastMonth(date));// 计算月同比
			condition = String.format(PATTEN_GENERAL, now, lastDay, lastWeek, lastMonth, cate.getDBName());
			list = nfService.getListByConditon(null, condition, null);
			map = groupByField(list,"stat_date");
		}

		// 计算每天的数据
		List<List<String>> result = new ArrayList<List<String>>();
		result.add(calculate(map.get(now)));
		result.add(calculate(map.get(lastDay)));
		result.add(calculate(map.get(lastWeek)));
		result.add(calculate(map.get(lastMonth)));

		// 根据每天的数据计算比率
		Iterator<List<String>> it = result.iterator();
		List<String> yset = it.next();
		int inloop = yset.size();
		while (it.hasNext()) {
			List<String> in = it.next();
			if (in.isEmpty()) {
				continue;
			}
			for (int i = 0; i < inloop; i++) {
				in.set(i, DNumberUtils.format((Double.valueOf(yset.get(i)) / Double.valueOf(in.get(i)) - 1) * 100));
			}
		}
		return result;

	}

	/**
	 * 根据类别和指标查询趋势数据---默认20140101--昨天的数据 返回json对象{time:[],data:[]}
	 * 
	 * @param cate
	 * @param index
	 * @author guolu 2015-1-26
	 */
	public static String getLine_Day(EnumCate cate, NetFlowIndex index,String dateGroup) {
		// 按默认时间查询某个类别的所有数据---每个日期一条数据
		List<NetFlow> list = nfService.getListByConditon(index.getColumnByGroup(dateGroup), index.getLineConditon(cate, dateGroup), dateGroup);

		TreeMap<String, List<NetFlow>> stat_dateMap = new TreeMap<String, List<NetFlow>>(groupByField(list,dateGroup));
		List<Number> curList = new ArrayList<Number>();
		// vppv/uv比较特殊
		for (String date : stat_dateMap.keySet()) {
				NetFlow nf = getByColVal(NetFlow.class,stat_dateMap.get(date),dateGroup,date);
				curList.add(getNetFlowValue(nf,index));
		}

		JSONObject ob = new JSONObject();
		ob.put("time", stat_dateMap.keySet());
		ob.put("data", curList);

		return ob.toString();
	}
	
	/**
	 * 获取三端流量数据的data
	 * @param cate
	 * @param index
	 * @return
	 * @author zhaoxiang 2015-01-29
	 */
	public static String getPlatformJson(EnumCate cate, NetFlowIndex index,String dateGroup){
		String platforms[] ={"PC","M","APP"};
		List<NetFlow> list = nfService.getListByConditon(index.getColumnByGroup(dateGroup+",platform"), index.getPlatformCon(cate,dateGroup+",platform"), dateGroup);
		TreeMap<String, List<NetFlow>> stat_dateMap = new TreeMap<String, List<NetFlow>>( groupByField(list,dateGroup));

		HashMap<String, List<Number>> dataMap = new HashMap<String, List<Number>>(); // platform : [dataList]
		// vppv/uv比较特殊
		for (String date : stat_dateMap.keySet()) {
			for (String plat : platforms) {
				List<Number> curList = dataMap.get(plat);
				if(curList == null)
					curList = new ArrayList<Number>();
				NetFlow nf = getByColVal(NetFlow.class,stat_dateMap.get(date),"platform",plat);
				curList.add(getNetFlowValue(nf,index));
				dataMap.put(plat, curList);
			}
		}

		JSONObject ob = new JSONObject();
		ob.put("time", stat_dateMap.keySet());
		for(String p:dataMap.keySet()){
			ob.put(p, dataMap.get(p));
		}

		return ob.toString();
	}
	
	/**
	 * 获取 “三端流量分别占总三端的比值” 数据的data
	 * @param cate
	 * @param index
	 * @return
	 * @author zhaoxiang 2015-01-29
	 */
	public static String getPlatformRateJson(EnumCate cate, NetFlowIndex index,String dateGroup){
		String platforms[] ={"PC","M","APP"};
		List<NetFlow> list = nfService.getListByConditon(EnumPlatform.getPlatRateColumn(index, cate, dateGroup+",platform"), EnumPlatform.getPlatformRateCon(index, cate,dateGroup+",platform"), dateGroup);
		TreeMap<String, List<NetFlow>> stat_dateMap = new TreeMap<String, List<NetFlow>>( groupByField(list,dateGroup));

		HashMap<String, List<String>> dataMap = new HashMap<String, List<String>>(); // platform : [dataList]
		
		List<String> timeList = Lists.newArrayList();
		for (String date : stat_dateMap.keySet()) {
			int count = 0;
			for (String plat : platforms) {
				List<String> curList = dataMap.get(plat);
				if(curList == null)
					curList = new ArrayList<String>();
				NetFlow nf = getByColVal(NetFlow.class,stat_dateMap.get(date),"platform",plat);
				double val = getNetFlowValue(nf,index).doubleValue();
				if(Double.compare(val, 0) == 0){
					count++;
					continue;
				}
				curList.add(DNumberUtils.format(val/100));
				dataMap.put(plat, curList);
			}
			if(count != 3){
				timeList.add(date);
			}
		}

		JSONObject ob = new JSONObject();
		ob.put("time", timeList);
		for(String p:dataMap.keySet()){
			ob.put(p, dataMap.get(p));
		}

		return ob.toString();
	}
	
	
	/**
	 * 获取各业务线流量数据的data
	 * @param index
	 * @return
	 * @author zhaoxiang 2015-01-29
	 */
	public static String getCateTotal_DayJson(EnumCate cate,NetFlowIndex index,String dateGroup){
		JSONArray cates = JSON.parseArray("["+cate.getCateOneNames()+"]");
		String groupBy = dateGroup+",if(cate1_name in ("+cate.getCateOneNames()+"),cate1_name,'其他')";
		if(EnumCate.total.equals(cate))
			groupBy = dateGroup+",business_name";
		List<NetFlowCate> list = nfCateService.getListByConditon(index.getColumnByGroup(groupBy+" as cateName"), cate.getNetFlowCateCon(index,dateGroup+",cateName"), dateGroup);
		
		HashMap<String, List<Number>> dataMap = new HashMap<String, List<Number>>(); // cate : [dataList]
		TreeMap<String, List<NetFlowCate>> stat_dateMap = new TreeMap<String, List<NetFlowCate>>(groupByField(list,dateGroup));

		for (String date : stat_dateMap.keySet()) {
			for (int i=0;i< cates.size();i++) {
				String c = cates.getString(i);
				List<Number> curList = dataMap.get(c);
				if(curList == null)
					curList = new ArrayList<Number>();
				NetFlowCate nf = getByColVal(NetFlowCate.class,stat_dateMap.get(date),"cateName",c);
				curList.add(getNetFlowValue(nf,index));
				dataMap.put(c, curList);
			}
		}

		JSONObject ob = new JSONObject();
		ob.put("time", stat_dateMap.keySet());
		for(String p:dataMap.keySet()){
			ob.put(p, dataMap.get(p));
		}
		ob.put("cateList", cates);
		return ob.toString();
	}

	/**
	 * 获取流量来源数据的data
	 * @param sourceField值: source或者source1
	 * @return
	 * @author zhaoxiang 2015-01-29
	 */
	public static String getSourceDataJson(EnumCate cate,NetFlowIndex index,EnumPlatform platEnum,String sourceField, String dateGroup){
		JSONArray cates = JSON.parseArray("["+EnumSource.getSources(sourceField+"_"+platEnum.toString())+"]");
		
		String groupBy = dateGroup+","+sourceField;
		
		List<NetFlowSource> list = nfSourceService.getListByConditon(index.getColumnByGroup(groupBy), index.getSourceCon(cate,platEnum, groupBy), dateGroup);
		
		HashMap<String, List<Number>> dataMap = new HashMap<String, List<Number>>(); // cate : [dataList]
		TreeMap<String, List<NetFlowSource>> stat_dateMap = new TreeMap<String, List<NetFlowSource>>(groupByField(list,dateGroup));
		// vppv/uv比较特殊
		for (String date : stat_dateMap.keySet()) {
			for (int i=0;i< cates.size();i++) {
				String c = cates.getString(i);
				List<Number> curList = dataMap.get(c);
				if(curList == null)
					curList = new ArrayList<Number>();
				NetFlowSource nf = getByColVal(NetFlowSource.class,stat_dateMap.get(date),sourceField,c);
				curList.add(getNetFlowValue(nf,index));
				dataMap.put(c, curList);
			}
		}

		JSONObject ob = new JSONObject();
		ob.put("time", stat_dateMap.keySet());
		for(String p:dataMap.keySet()){
			ob.put(p, dataMap.get(p));
		}
		ob.put("cateList", cates);
		return ob.toString();
	}

	/**
	 * 选定一级来源获取指定的二级来源的数据, 二级来源“趋势图” 
	 * @return
	 * @author zhaoxiang 2015-04-21
	 */
	public static String getSourceDataTwoJson(EnumCate cate,NetFlowIndex index,EnumPlatform platEnum,String source1, String dateGroup){
		JSONArray cates = JSON.parseArray("["+EnumSource.getSources("source2_"+platEnum+"_"+source1)+"]");
		
		String groupBy = dateGroup+",source2_name";
		
		List<NetFlowSource> list = nfSourceService.getListByConditon(index.getColumnByGroup(groupBy), EnumSource.getSourceTwoCon(index,cate,platEnum,source1,groupBy), dateGroup);
		
		HashMap<String, List<Number>> dataMap = new HashMap<String, List<Number>>(); // cate : [dataList]
		TreeMap<String, List<NetFlowSource>> stat_dateMap = new TreeMap<String, List<NetFlowSource>>(groupByField(list,dateGroup));
		// vppv/uv比较特殊
		for (String date : stat_dateMap.keySet()) {
			for (int i=0;i< cates.size();i++) {
				String c = cates.getString(i);
				List<Number> curList = dataMap.get(c);
				if(curList == null)
					curList = new ArrayList<Number>();
				NetFlowSource nf = getByColVal(NetFlowSource.class,stat_dateMap.get(date),"source2_name",c);
				curList.add(getNetFlowValue(nf,index));
				dataMap.put(c, curList);
			}
		}

		JSONObject ob = new JSONObject();
		ob.put("time", stat_dateMap.keySet());
		for(String p:dataMap.keySet()){
			ob.put(p, dataMap.get(p));
		}
		ob.put("cateList", cates);
		return ob.toString();
	}

	

	/**
	 * 获取流量3级来源  “饼图” 
	 * @return
	 * @author zhaoxiang 2015-07-06
	 */
	public static String getSource3PieDataJson(String businessName,String source2,EnumPlatform plat,String beginDate,String endDate){
		EnumCate cate = EnumCate.valueOf(businessName);
		//top5的source3
		List<String> source3List_top = Lists.newArrayList();
		String condition = EnumSource.getSource3PieCon(cate.getDBName(), source2, beginDate, endDate);
		String columns = EnumSource.getSource3PieTopNCols();
		List<NetFlowSource_Three> list = nfSourceThreeService.getListByPage(condition, columns, 1, 5, "uv desc");
		
		for (Object  sourceVo: list) {
			Object sourceName = ReflectUtil.getVal(sourceVo,"source3_name");
			source3List_top.add((String)sourceName);
		}
		//再查一次，非top5的归为‘其他’
		String topSources = StringUtils.join(source3List_top, "','");
		list = nfSourceThreeService.getListByConditon(EnumSource.getSource3PieCols(topSources), condition, "uv desc");

		List<Object> source3NameList = Lists.newArrayList();
		List<Object> dataList = Lists.newArrayList();
		
		for (Object  sourceVo: list) {
			Object sourceName = ReflectUtil.getVal(sourceVo,"source3_name");
			Object uv = ReflectUtil.getVal(sourceVo,"uv");
			JSONObject item = new JSONObject();
			item.put("value", uv);
			item.put("name", sourceName);
			dataList.add(item);
			source3NameList.add(sourceName);
		}
		
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("source3NameList", source3NameList);
		jsonObject.put("source3List_top", source3List_top);
		jsonObject.put("dataList", dataList);
		return jsonObject.toString();
	}	

	/**
	 * 获取流量3级来源  “曲线图” 
	 * @return
	 * @author zhaoxiang 2015-07-06
	 */
	public static String getSource3LineDataJson(String businessName, String dateGroup, String source2, String source3s,NetFlowIndex index){
		
		String groupBy = dateGroup+",source3_name";

		Iterable<String> topNSourcesArray = Splitter.on("','").split(source3s);
		String condition = EnumSource.getSource3LineCon(index,EnumCate.valueOf(businessName),EnumPlatform.m,source2, source3s,groupBy);
		String columns = index.getColumnByGroup(groupBy);
		List<NetFlowSource_Three> list = nfSourceThreeService.getListByConditon(columns, condition, null);

		HashMap<String, List<Number>> dataMap = new HashMap<String, List<Number>>(); // cate : [dataList]
		TreeMap<String, List<NetFlowSource_Three>> stat_dateMap = new TreeMap<String, List<NetFlowSource_Three>>(ReflectUtil.groupByField(list,dateGroup));
		// vppv/uv比较特殊
		for (String date : stat_dateMap.keySet()) {
			for(String c : topNSourcesArray){
				List<Number> curList = dataMap.get(c);
				if(curList == null)
					curList = new ArrayList<Number>();
				NetFlowSource_Three nf = getByColVal(NetFlowSource_Three.class,stat_dateMap.get(date),"source3_name",c);
				curList.add(getNetFlowValue(nf,index));
				dataMap.put(c, curList);
			}
		}
		
		
		JSONObject jsonObject = new JSONObject(); 	
		jsonObject.put("time", stat_dateMap.keySet());
		jsonObject.put("source3NameList", topNSourcesArray);
		jsonObject.putAll(dataMap);
		return jsonObject.toString();
	}

	
	/**
	 * 获取流量二级来源  “饼图” 
	 * @return
	 * @author zhaoxiang 2015-03-16
	 */
	public static String getSourceTwoPieDataJson(EnumCate cate,NetFlowIndex index,EnumPlatform platEnum,String beginDate,String endDate){
		JSONArray source1List = JSON.parseArray("["+EnumSource.getSources("source1_"+platEnum)+"]");
		
		String groupBy = "source1_name, source2_name";
		
		List<NetFlowSource> list = nfSourceService.getListByConditon(index.getColumnByGroup(groupBy), EnumSource.getSourceTwoPieCon(index,cate,platEnum,beginDate,endDate, groupBy), null);
		
		JSONObject jsonObject = new JSONObject(); 	//{source1NameList: [], source1_JSONArray:[{},{}], {source1: {source2NameList: [], source2_JSONArray:[]}} }
		long maxVal1 = 0;
		JSONArray source1_JSONArray = new JSONArray();	//[{},{}]
		
		TreeMap<String, List<NetFlowSource>> source1_dateMap = new TreeMap<String, List<NetFlowSource>>(groupByField(list,"source1_name"));
		for (String  source1: source1_dateMap.keySet()) {
			JSONObject source1JSON = new JSONObject();
			
			JSONObject source2JSONObj = new JSONObject(); //{source2NameList: [], source2_JSONArray:[{},{}]}
			Set<String> source2NameSet = new HashSet<String>();
			JSONArray source2_JSONArray = new JSONArray();
			
			
			long maxVal2 = 0;
			List<NetFlowSource> source2_list = source1_dateMap.get(source1);
			for(NetFlowSource source2Vo : source2_list){
				if(StringUtils.equals(source2Vo.getSource2_name(),"all")){
					source1JSON.put("name",source1);
					long val1 = (long) Math.ceil(setSourceValue(index, source1JSON, source2Vo));
					if(maxVal1 < val1){
						maxVal1 = val1;
					}
					if(source2_list.size() == 1){
						source2Vo.setSource2_name(source2Vo.getSource1_name());
					}else{
						continue;
					}
				}
				source2NameSet.add(source2Vo.getSource2_name());
				JSONObject source2JSON = new JSONObject();
				source2JSON.put("name", source2Vo.getSource2_name());
				long val2 = (long) Math.ceil(setSourceValue(index, source2JSON, source2Vo));
				if(maxVal2 < val2){
					maxVal2 = val2;
				}
				source2_JSONArray.add(source2JSON);
			}
			source2JSONObj.put("source2NameList", source2NameSet);
			source2JSONObj.put("source2DataList", source2_JSONArray);
			source2JSONObj.put("max", maxVal2);
			jsonObject.put(source1, source2JSONObj);
			if(source1List.contains(source1JSON.get("name"))){
				source1_JSONArray.add(source1JSON);
			}
		}

		jsonObject.put("source1NameList", source1List);
		jsonObject.put("source1DataList", source1_JSONArray);
		jsonObject.put("max", maxVal1);
		jsonObject.put("beginDate", beginDate);
		jsonObject.put("endDate", endDate);

		return jsonObject.toString();
	}	

	
	private static double setSourceValue(NetFlowIndex index, JSONObject ob,NetFlowSource sourceVo){
		Long voPV = (Long) getVal(sourceVo,"pv");
		Long voUV = (Long) getVal(sourceVo,"uv");
		switch (index) {
			case pv:
			case vppv:
			case lide_pv:
				ob.put("value", voPV);
				return voPV;
			case uv:
			case lide_uv:
				ob.put("value", voUV);
				return voUV;
			case pvDIVuv:
				double pvDIVuv = DNumberUtils.formatDouble((Double) getVal(sourceVo,"pvDIVuv"));
				return pvDIVuv;
			case vppvDIVuv:
				double vppvDIVuv = DNumberUtils.formatDouble((Double) getVal(sourceVo,"vppvDIVuv"));
				ob.put("value",vppvDIVuv);
				return vppvDIVuv;
			default:
				break;
		}
		return 0;
	}
	
	/**
	 * 全站热门城市UV排行TOP30 data
	 * @param cate
	 * @param index
	 * @return
	 * @author zhaoxiang 2015-02-05
	 * @param cateEnum 
	 */
	public static List<NetFlowCity> getUVTop30City(EnumCate cateEnum, EnumPlatform plat,String stat_date){
		//先查询全国总UV,再计算top30城市数据,计算UV占比
		List<NetFlowCity> list = nfCityService.getListByPage( EnumCity.getTopNCon(cateEnum,stat_date), EnumCity.getTopNColumns(plat.getColName()),1, 31, "uv desc");
		long totalUV = 0;
		if(CollectionUtils.isEmpty(list)){
			return null;
		}else {
			NetFlowCity allCityVo = list.get(0);
			allCityVo.setCity_name("全国");
			totalUV = allCityVo.getUv();
		}
		
		for (int i=0;i<list.size();i++) {
			NetFlowCity vo = list.get(i);
			vo.setUvRatio(VelocityTools.compRateDirect(vo.getUv(), totalUV));
			vo.setVppvDIVuv(DNumberUtils.formatDouble(vo.getVppvDIVuv()));
		}
		
		return list;
	}
	
	/**
	 * 全站热门城市地图数据
	 * @param cate
	 * @param index
	 * @return
	 * @author zhaoxiang 2015-02-05
	 */
	public static String getUVCityJson(String date,EnumPlatform plat,EnumCate cateEnum){
		//先查询全国各省的UV
		List<NetFlowCity> privinceList = nfCityService.getListByConditon("province_name as city_name,"+EnumCity.getUVColumns(plat.getColName()), EnumCity.getUVCon(date,cateEnum,"province_name"), null);
		List<NetFlowCity> cityList = nfCityService.getListByConditon("city_name,"+EnumCity.getUVColumns(plat.getColName()), EnumCity.getUVCon(date,cateEnum,"city_name"), null);
		
		ArrayList<NetFlowCity> dataList =  new ArrayList<NetFlowCity>();
		dataList.addAll(privinceList);
		dataList.addAll(cityList);
		
		Set<String> dealedCity = new HashSet<String>();
		JSONArray array = new JSONArray();
		for(NetFlowCity vo: dataList){
			if(dealedCity.contains(vo.getCity_name()))
				continue;
			dealedCity.add(vo.getCity_name());
			JSONObject jsonObject = new JSONObject();
		    jsonObject.put("name", vo.getCity_name());
		    jsonObject.put("value", vo.getUv());
		    array.add(jsonObject);
		}
		
		return array.toString();
	}
	
	/**PC搜索词TOP N
	 * @param searchDate
	 * @param type
	 * @return
	 */
	public static  List<SearchWord> getTopNSearchWords(String searchDate,String type,String businessName){
		EnumCate cateEnum = EnumCate.valueOf(businessName);
		String condition = "stat_date='%s' and type='%s' and business_name='" + cateEnum.getDBName()  + "'";
		return  searchWordService.getListByPage(String.format(condition, searchDate,type), "*", 1, 30, "rank");
	}
	
	/**
	 * M端搜索词TOP N
	 * @param searchDate
	 * @param type
	 * @return
	 */
	public static  List<SearchWord_M> getTopNSearchWords_M(String searchDate,String type,String businessName){
		EnumCate cateEnum = EnumCate.valueOf(businessName);
		String condition = "stat_date='%s' and type='%s' and business_name='" + cateEnum.getDBName()  + "'";
		return  searchWordService_M.getListByPage(String.format(condition, searchDate,type), "*", 1, 30, "rank");
	}
	
//	@SuppressWarnings({ "rawtypes", "unchecked" })
//	public static String getCityCate2Json(EnumCate busEnum,String city1,String cate2,NetFlowIndex index, String dateGroup){
//		if(EnumCate.total.equals(busEnum) || EnumCate.ershouche.equals(busEnum))
//			return "";
//		
//		String platforms[] ={"PC","M","APP"};
//		Class beanClas= busEnum.getCityCateBeanCls();
//		AbstractBaseService  nfs = ServiceBeanFactory.get(beanClas,null); //busEnum.getCityCateService();
//		String groupBy = dateGroup+",platform";
//
//		List list = nfs.getListByConditon(index.getColumnByGroup(groupBy), busEnum.getCityCateCon(index, city1, cate2,groupBy), null);
//		
//		HashMap<String, List<Number>> dataMap = new HashMap<String, List<Number>>(); // cate : [dataList]
//		TreeMap<String, List<?>> stat_dateMap = new TreeMap<String, List<?>>(groupByField(list,dateGroup));
//
//		for (String date : stat_dateMap.keySet()) {
//			for (String plat : platforms) {
//				List<Number> curList = dataMap.get(plat);
//				if(curList == null)
//					curList = new ArrayList<Number>();
//				Object nf = getByColVal(beanClas,stat_dateMap.get(date),"platform",plat);
//				curList.add(getNetFlowValue(nf,index));
//				dataMap.put(plat, curList);
//			}
//		}
//
//		JSONObject ob = new JSONObject();
//		ob.put("time", stat_dateMap.keySet());
//		for(String p:dataMap.keySet()){
//			ob.put(p, dataMap.get(p));
//		}
//
//		return ob.toString();
//	}
	

	public static String getCityCate2Json(EnumCate busEnum,String city1,String cate2,NetFlowIndex index, String dateGroup){
		if(EnumCate.total.equals(busEnum) || EnumCate.ershouche.equals(busEnum))
			return "";
		
		String platforms[] ={"PC","M","APP"};
		Class<NetFlowCityCate> beanClas = NetFlowCityCate.class;
		AbstractBaseService<NetFlowCityCate>  nfs = ServiceBeanFactory.get(beanClas,null); //busEnum.getCityCateService();
		String groupBy = dateGroup+",platform";

		String tableSuffix = "_"+busEnum.name()+"_city_cate";
		List<NetFlowCityCate> list = nfs.getListByConditon(tableSuffix,index.getColumnByGroup(groupBy), busEnum.getCityCateCon(index, city1, cate2,groupBy), null);
		
		HashMap<String, List<Number>> dataMap = new HashMap<String, List<Number>>(); // cate : [dataList]
		TreeMap<String, List<NetFlowCityCate>> stat_dateMap = new TreeMap<String, List<NetFlowCityCate>>(groupByField(list,dateGroup));

		for (String date : stat_dateMap.keySet()) {
			for (String plat : platforms) {
				List<Number> curList = dataMap.get(plat);
				if(curList == null)
					curList = new ArrayList<Number>();
				Object nf = getByColVal(beanClas,stat_dateMap.get(date),"platform",plat);
				curList.add(getNetFlowValue(nf,index));
				dataMap.put(plat, curList);
			}
		}

		JSONObject ob = new JSONObject();
		ob.put("time", stat_dateMap.keySet());
		for(String p:dataMap.keySet()){
			ob.put(p, dataMap.get(p));
		}

		return ob.toString();
	}
	
	
	private static <T>  T getByColVal(Class<T> clas, List<T> list,String column,String value) {
		try {
			if (list == null || list.isEmpty()) {
				return clas.newInstance();
			}
				
			for (T vo : list) {
				Object curVal =  getVal(vo, column);
				if (StringUtils.equalsIgnoreCase(String.valueOf(curVal), value)) {
					return vo;
				}
			}
			return clas.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}


	private static <T> Map<String, List<T>> groupByField(List<T> list,String fieldName) {
		Map<String, List<T>> map = new HashMap<String, List<T>>();
		for (T vo : list) {
			String date = (String) getVal(vo, fieldName);
			if (!map.containsKey(date)) {
				map.put(date, new ArrayList<T>());
			}
			map.get(date).add(vo);
		}
		return map;
	}
	
	/**
	 * 
	 * @param list
	 * @return
	 * @author guolu 2015-1-27
	 */
	private static List<String> calculate(List<NetFlow> list) {
		if (list == null || list.isEmpty()) {
			return Collections.emptyList();
		}
		int pv = 0;
		int uv = 0;
		int vppv = 0;
		int lide_pv = 0;
		int lide_uv = 0;
		for (NetFlow nf : list) {
			if (StringUtils.equals(nf.getPage_type(), EnumPageType.total.getDBName())) {
				pv += nf.getPv();
				uv += nf.getUv();
			} else if (StringUtils.equals(nf.getPage_type(), EnumPageType.detail.getDBName())) {
				vppv += nf.getPv();
			} else if (StringUtils.equals(nf.getPage_type(), EnumPageType.listanddetail.getDBName())) {
				lide_pv += nf.getPv();
				lide_uv += nf.getUv();
			}
		}
		List<String> result = new ArrayList<String>();
		result.add(DNumberUtils.format(pv));
		result.add(DNumberUtils.format(uv));
		result.add(DNumberUtils.format(vppv));
		result.add(DNumberUtils.format(lide_pv));
		result.add(DNumberUtils.format(lide_uv));
		result.add(DNumberUtils.format((double) pv / (double) uv));
		result.add(DNumberUtils.format((double) vppv / (double) uv));
		return result;
	}

	/**
	 * 获取月独立MAU数据
	 * @param cate
	 * @param index
	 * @return
	 * @author zhaoxiang 2015-07-14
	 */
	public static String getMAUDataJson(String businessName, String index){
		if(StringUtils.equalsIgnoreCase(businessName, "total")){
			businessName = "all";
		}
		String condition = "business_name='%s'";
		String platforms[] ={"PC","M","APP"};
		List<NetFlowMAU> list = mauService.getListByConditon("month,platform,"+index, String.format(condition, businessName), null);
		TreeMap<String, List<NetFlowMAU>> stat_dateMap = new TreeMap<String, List<NetFlowMAU>>( ReflectUtil.groupByField(list,"month"));

		HashMap<String, List<Object>> dataMap = new HashMap<String, List<Object>>(); // platform : [dataList]
		
		for (String date : stat_dateMap.keySet()) {
			for (String plat : platforms) {
				List<Object> curList = dataMap.get(plat);
				if(curList == null)
					curList = Lists.newArrayList();
				NetFlowMAU vo = ReflectUtil.getByColVal(NetFlowMAU.class,stat_dateMap.get(date),"platform",plat);
				Object value = ReflectUtil.getVal(vo, index);
				curList.add(value==null ? 0 : value);
				dataMap.put(plat, curList);
			}
		}

		JSONObject ob = new JSONObject();
		ob.put("time", stat_dateMap.keySet());
		for(String p:dataMap.keySet()){
			ob.put(p, dataMap.get(p));
		}

		return ob.toString();
	}


private static final String VISITPATH_CON="stat_date='%s' AND source='all' AND biz_name='%s' AND platform='%s'";
	public static String getVisitPathDataJson(String businessName, String platform, String stat_date) {
	List<VisitPath> list = visitPathService.getListByConditon("path_json", String.format(VISITPATH_CON, stat_date,businessName,platform), "depth");
	JSONArray array = new JSONArray();
	for(VisitPath v : list){
		array.add(JSONObject.parse(v.getPath_json()));
	}
	return array.toString();
	}
	

/**
 * 获取流量来源数据       流量传递及消失
 */

private static final String TRAFFICFLOW_CON="business_type_from='%s' AND business_type_to='%s' AND disp_cate1_name_from='%s' AND disp_cate1_name_to='%s'"
	    		+ " AND (page_type_from in (%s) AND page_type_to in(%s) ) AND disp_cate2_name_from='all' AND stat_date='%s'";
private static final String SOURCEFLOW_CON="business_type_from='%s' AND business_type_to='%s' AND source1='%s' AND source2='%s'"
		+ " AND (page_type_from in (%s) AND page_type_to in(%s) ) AND stat_date='%s'";
public static String getFlowDataJson(String plat,String business_from,String  business_to,String  cate_from_or_source_from,String cate_to_or_source_to,String page_from,String page_to,String platform,String stat_date,String option)  {
	//格式化日期
	stat_date = stat_date.substring(0,4)+"-"+stat_date.substring(5,7)+"-"+stat_date.substring(8,10);
	if("".equals(cate_from_or_source_from)){
		cate_from_or_source_from = "all";
	}
	if("".equals(cate_to_or_source_to)){
		cate_to_or_source_to = "all";
	}
	//默认的page_type
	String page_type = "'deliver','detail', 'empty', 'home', 'index', 'jianli_detail', 'land_page', 'list','login','my','others','post','qy_detail','vip'";
	//对page_from跟page_to类型进行字符分割
	String page_from_sql = "";
	String page_to_sql = "";
	String[] Arr1 = page_from.split(",");
	String[] Arr2 = page_to.split(",");
	for (String string : Arr1) {
		String page_from_new = "'%s',";
		page_from_sql += String.format(page_from_new,string);
	}
	for (String string : Arr2) {
		String page_to_new = "'%s',";
		page_to_sql += String.format(page_to_new,string);
	}
	page_to_sql = page_to_sql.substring(0, page_to_sql.length()-1);
	page_from_sql = page_from_sql.substring(0, page_from_sql.length()-1);
		
		
	String condition = "";
	if(business_from.equals("total")){
		business_from = "all";		
	}
	if(business_to.equals("total")){
		business_to = "all";
	}
	//两种都是全部类型
	if("全部".equals(page_from)){
		page_from_sql = page_type;
	}
	if("全部".equals(page_to)){
		page_to_sql = page_type;
	}
	
	String tableSuffix = stat_date.substring(0,4)+stat_date.substring(5,7);	
	
	JSONArray array = new JSONArray();
	if(!"trafficFlow".equals(option)){
		tableSuffix = plat+"_source_"+tableSuffix;
		condition = String.format(SOURCEFLOW_CON, business_from,business_to,cate_from_or_source_from,cate_to_or_source_to,page_from_sql,page_to_sql,stat_date);
		
		List<SourceFlow> list = sourceFlowService.getListByConditon(tableSuffix,"page_type_from,page_type_to,"+platform,condition, " page_type_from ");
		
		int i = 0;
		if(list.size()>0){
			for (SourceFlow sourceFlow : list) {				
				JSONObject json1 = new JSONObject();
				String key = i+"";
				String value = sourceFlow.getPage_type_from()+","+sourceFlow.getPage_type_to()+",";
				if("pv".equals(platform)){
					value += sourceFlow.getPv();
				}else{
					value += sourceFlow.getUv();
				}
				json1.put(key, value);
				array.add(json1);	
				i++;
				
			}	
		}	
		
	}else{
		tableSuffix = plat+"_cate_"+tableSuffix;
		condition = String.format(TRAFFICFLOW_CON, business_from,business_to,cate_from_or_source_from,cate_to_or_source_to,page_from_sql,page_to_sql,stat_date);
		List<TrafficFlow> list = trafficFlowService.getListByConditon(tableSuffix,"page_type_from,page_type_to,"+platform,condition, " page_type_from ");
		int i = 0;
		if(list.size()>0){
			for (TrafficFlow trafficFlow : list) {	
				
				JSONObject json1 = new JSONObject();
				String key = i+"";
				String value = trafficFlow.getPage_type_from()+","+trafficFlow.getPage_type_to()+",";
				if("pv".equals(platform)){
					value += trafficFlow.getPv();
				}else{
					value += trafficFlow.getUv();
				}
				json1.put(key, value);
				array.add(json1);	
				i++;

			}	
		}	
	}
	return array.toString();
	
	}

  /**
   *根据业务线切换类别
   */
private static final String GETCATE_CON="%s='%s' and stat_date='%s'";
   public static String getCateByBusiness(String plat,String business_from_or_to,String business,String stat_date,String option){
	
	   //格式化日期
	   stat_date = stat_date.substring(0,4)+"-"+stat_date.substring(5,7)+"-"+stat_date.substring(8,10);
	   String tableSuffix = stat_date.substring(0,4)+stat_date.substring(5,7);	
	   String condition = "";
	   String cols = "";
	   JSONObject json = new JSONObject();
	   condition = String.format(GETCATE_CON, business_from_or_to,business,stat_date);
	   
	   List<String> cateList = Lists.newArrayList();
	   if("trafficflow".equals(option)){
		    tableSuffix = plat+"_cate_"+tableSuffix;
		    if("business_type_from".equals(business_from_or_to)){
		    	cols =  "DISTINCT disp_cate1_name_from";
		    	List<TrafficFlow> list = trafficFlowService.getListByConditon(tableSuffix,cols,condition, null);
		    	if(list.size()>0){  
			    	for (TrafficFlow trafficFlow : list) {
						cateList.add(trafficFlow.getDisp_cate1_name_from());
					}
		    	}
		    }else{
		    	cols =  "DISTINCT disp_cate1_name_to";
		    	List<TrafficFlow> list = trafficFlowService.getListByConditon(tableSuffix,cols,condition, null);
		    	if(list.size()>0){  
			    	for (TrafficFlow trafficFlow : list) {
						cateList.add(trafficFlow.getDisp_cate1_name_to());
					}
		    	}
		    }
		    
	   }else{
		   tableSuffix = plat+"_source_"+tableSuffix;
		   if("business_type_from".equals(business_from_or_to)){
		    	cols =  "DISTINCT source1";		   
		    	List<SourceFlow> list = sourceFlowService.getListByConditon(tableSuffix,cols,"stat_date='"+stat_date+"'", null);
			    if(list.size()>0){    	
			    	for (SourceFlow sourceFlow : list) {
			    		cateList.add(sourceFlow.getSource1());
			    	}
			    }
		    }else{
		    	cols =  "DISTINCT source2";
		    	List<SourceFlow> list = sourceFlowService.getListByConditon(tableSuffix,cols,condition, null);
		    	if(list.size()>0){  
		    	for (SourceFlow sourceFlow : list) {
						cateList.add(sourceFlow.getSource2());
					}
		    	}
		    }
		  
	   }
	   json.put("cateList", cateList);
	   return json.toString();
	   
   }

   
private static final String VISITPATHNEW_CON="stat_date='%s'  AND biz_name='%s' AND platform='%s' AND %s='%s' AND action_type='%s' AND count_type='%s'";
public static String getVisitPathNewDataJson(String businessName, String platform, String stat_date,String cate,String actionType,String plat,String option) {
	List<VisitPathNew> list = null;
	//品类
	if("cate_name".equals(option)){		
		list = visitPathNewService.getListByConditon("path_json", String.format(VISITPATHNEW_CON, stat_date,businessName,platform,option,cate,actionType,plat)+" AND source='all'", "depth");
	}else{
		list = visitPathNewService.getListByConditon("path_json", String.format(VISITPATHNEW_CON, stat_date,businessName,platform,"source",cate,actionType,plat)+" AND cate_name='all'", "depth");
	}
	
	JSONArray array = new JSONArray();
	for(VisitPathNew v : list){
		array.add(JSONObject.parse(v.getPath_json()));
	}
	return array.toString();
	}

public static List<String> getPathCate(String cateName,String businessName) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
	
	List<String> list = Lists.newArrayList();
	String getter = "get"+cateName.substring(0,1).toUpperCase()+cateName.substring(1);
	Method[] methods = VisitPathNew.class.getDeclaredMethods();
	Method method = null;
	for (Method method2 : methods) {
		if(getter.equals(method2.getName())){
			method = method2;
			break;
		}		
	}
	boolean flag = false;
	List<VisitPathNew> lists = visitPathNewService.getListByConditon("DISTINCT "+cateName,businessName, cateName);
	for (VisitPathNew visitPathNew : lists) {
		Object cate = method.invoke(visitPathNew); 
		if(cate.toString().equals("all")){
			flag = true;
			continue;
		}
		list.add(cate.toString());
	}
	if(flag){
		list.add(0, "all");
	}
	return list;
	
}


}


